package com.priox.sigar.jsf;

import com.mm.support.mapper.DTOMapperService;
import com.priox.sigar.application.acreedor.RegistroAcreedorApp;
import com.priox.sigar.application.mappers.AcreedorMapper;
import com.priox.sigar.application.mappers.GrupoEmpresarialMapper;
import com.priox.sigar.application.mappers.SociedadMapper;
import com.priox.sigar.client.dto.*;
import com.priox.sigar.client.flt.AcreedorFlt;
import com.priox.sigar.client.flt.SociedadFlt;
import com.priox.sigar.domain.model.Acreedor;
import com.priox.sigar.domain.model.AcreedorSociedad;
import com.priox.sigar.domain.model.ClienteSociedad;
import com.priox.sigar.domain.model.constantes.Constantes;
import com.priox.sigar.domain.model.constantes.PathConstant;
import com.priox.sigar.enums.ActivoInactivo;
import com.priox.sigar.jsf.util.FindCrudBeanBase;
import com.priox.sigar.server.infrastructure.persistence.exception.ApplicationException;
import com.priox.sigar.util.FileUtil;
import com.priox.sigar.util.TimeObserver;
import org.apache.commons.lang3.StringUtils;
import org.primefaces.component.inputtext.InputText;
import org.primefaces.event.CloseEvent;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.event.RowEditEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.model.LazyDataModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.event.ActionEvent;
import javax.faces.event.AjaxBehaviorEvent;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;


@ManagedBean
@Scope("session")
@Component
public class MaestroAcreedorJsfBean extends FindCrudBeanBase {

    private static final Logger LOG = LoggerFactory.getLogger(MaestroAcreedorJsfBean.class);
    static AtomicLong workerId2 = new AtomicLong();
    private boolean borrarValor;
    AcreedorFlt filtroBusqueda;

    SociedadFlt filtroPick;

    AcreedorDTO nuevoRegistro;

    SociedadDTO nuevoRegistroDetalle;

    private LazyDataModel<AcreedorDTO> lazyModel;

    String archivoCarga;
    List<AcreedorDTO> registros = new ArrayList<AcreedorDTO>();
    List<AcreedorSociedadDTO> detalle = new ArrayList<AcreedorSociedadDTO>();
    List<SociedadDTO> detallePickList = new ArrayList<SociedadDTO>();

    List<GrupoEmpresarialDTO> cmbGrupoEmpresarial;
    List<SociedadDTO> cmbSociedad;
    protected DocumentoAcreedorDTO documentoAcreedorDTO = new DocumentoAcreedorDTO();

    @Autowired
    DTOMapperService mapperService;

    @Autowired
    AcreedorMapper acreedorMapper;

    @Autowired
    GrupoEmpresarialMapper grupoEmpresarialMapper;

    @Autowired
    SociedadMapper sociedadMapper;

    @Autowired
    RegistroAcreedorApp registroAcreedorApp;

    @Autowired
    @Qualifier("jobAcreedor")
    private Job jobAcreedor;

    @Autowired
    @Qualifier("jobDocumentoAcreedor")
    private Job jobDocumentoAcreedor;

    @Autowired
    private JobLauncher jobLauncher;


    @PostConstruct
    public void init() {
        filtroBusqueda = new AcreedorFlt();
        nuevoRegistro = new AcreedorDTO();
        cmbGrupoEmpresarial = grupoEmpresarialMapper.findAll();
    }

    /*Métodos de herencia*/

    public void showNewDialogSeleccion(ActionEvent actionEvent) {
        filtroPick = new SociedadFlt();
        detallePickList = new ArrayList<SociedadDTO>();
    }

    @Override
    public void setCursorTableNull() {

    }

    public void onFileUpload(FileUploadEvent event) {
        SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy-HHmmssSSS");
        String newFileName = "ACREEDOR_" + sdf.format(new Date()) + "_" + workerId2.incrementAndGet() + ".csv";
        documentoAcreedorDTO.getArchivos().add(newFileName);
        documentoAcreedorDTO.setNombreArchivo(newFileName);
        LOG.debug("DOCUMENTOS " + documentoAcreedorDTO.getArchivos().size() + "nombres1 " + documentoAcreedorDTO.getNombreArchivo());
        try {
            FileUtil.copyFile(event.getFile().getFileName(), event.getFile().getInputstream(), documentoAcreedorDTO.getNombreArchivo());

        } catch (IOException e) {
            e.printStackTrace();
            throw new ApplicationException("Error al copiar el archivo " + event.getFile().getFileName(), e);
        }
        archivoCarga = newFileName;

    }


    public void onSelectDetail(SelectEvent actionEvent) {
        if (nuevoRegistro != null) {
            detalle = sociedadMapper.findBySociedadAcreedorId(nuevoRegistro.getAcreedorId());
        } else {
            detalle = new ArrayList<AcreedorSociedadDTO>();
        }

    }

    public void procesar(ActionEvent actionEvent) {

        String archivo = PathConstant.DIR_TMP + File.separator + archivoCarga;
        JobParametersBuilder jpBuilder = new JobParametersBuilder()
                .addString("input.file.name", archivo);
        JobExecution execution = null;
        try {
            TimeObserver timeObserver = new TimeObserver("Lectura y escritura de acreedores");
            timeObserver.empezar();
            TimeObserver toBatch = new TimeObserver("Copiar a BD");
            toBatch.empezar();
            registroAcreedorApp.deleteAll();
            execution = jobLauncher.run(jobAcreedor, jpBuilder.toJobParameters());
            toBatch.terminar();
            LOG.debug(toBatch.mostrarMsg());
            if (ExitStatus.COMPLETED.equals(execution.getExitStatus())) {
                TimeObserver toSP = new TimeObserver("Copiar a BD");
                toSP.empezar();
                acreedorMapper.executeUpdateAcreedorSociedad();
                toSP.terminar();
                LOG.debug(toSP.mostrarMsg());
                findRegistros();
            }
            timeObserver.terminar();
            LOG.debug(timeObserver.mostrarMsg());
        } catch (Exception e) {
            throw new ApplicationException("Problemas al procesar el archivo batch", e);
        }


    }

    public void procesarDocumento(ActionEvent actionEvent) {
        if (StringUtils.isBlank(documentoAcreedorDTO.getNombreArchivo()) || documentoAcreedorDTO.getArchivos().isEmpty()) {
            throw new ApplicationException("El archivo no a sido cargado");
        }
        List<String> archivos = documentoAcreedorDTO.getArchivos();
        int totalInicial = 0;
        if (isBorrarValor()) {
            registroAcreedorApp.deleteDocumentoAll();
        } else {
            totalInicial = acreedorMapper.countDocumentoAcreedor();
        }

        for (String archivoLectura : archivos) {
            LOG.info("enviando a procesar el archivo  <" + archivoLectura + ">");
            String archivo = PathConstant.DIR_TMP + File.separator + archivoLectura;
            JobParametersBuilder jpBuilder = new JobParametersBuilder()
                    .addLong("input.usuarioId", getUser().getUsuarioId())
                    .addString("input.file.name", archivo);


            JobExecution execution = null;
            try {
                TimeObserver timeObserver = new TimeObserver("Lectura y escritura de documento acreedores");
                timeObserver.empezar();
                TimeObserver toBatch = new TimeObserver("Copiar a BD");
                toBatch.empezar();

                execution = jobLauncher.run(jobDocumentoAcreedor, jpBuilder.toJobParameters());
                toBatch.terminar();
                LOG.debug(toBatch.mostrarMsg());

                if (ExitStatus.COMPLETED.equals(execution.getExitStatus())) {
                    int totalFinal = acreedorMapper.countDocumentoAcreedor();
                    if(totalFinal==-1) totalFinal=0;
//                    totalDocumentos= acreedorMapper.totalDocumentos();
                    addMessage("EL archivo se cargo correctamente. Total de documentos insertados (" + (totalFinal - totalInicial) + ")", FacesMessage.SEVERITY_INFO);
                }


            } catch (Exception e) {
                documentoAcreedorDTO = new DocumentoAcreedorDTO();
                throw new ApplicationException("Problemas al procesar el archivo batch", e);
            }

        }

        documentoAcreedorDTO.getArchivos().clear();


    }

    public void onSelectGrupoEmpresarial(AjaxBehaviorEvent actionEvent) {
        if (filtroBusqueda.getGrupoEmpresarial() == null) {
            cmbSociedad = new ArrayList<SociedadDTO>();
        } else {
            cmbSociedad = sociedadMapper.findByGrupoEmpresarialId(filtroBusqueda.getGrupoEmpresarial().getGrupoEmpresarialId());
        }
    }

    @Override
    public void onNewRecord(ActionEvent actionEvent) {
        //To change body of implemented methods use File | Settings | File Templates.
        nuevoRegistro = new AcreedorDTO();
        nuevoRegistro.setEstado(ActivoInactivo.ACTIVO);
        updateMode = false;
        InputText inputText = (InputText) findComponent("inputCodigo");
        inputText.setDisabled(false);

    }

    @Override
    public void onShowEditDialog(ActionEvent actionEvent) {
        setUpdateMode(true);

        InputText inputText = (InputText) findComponent("inputCodigo");
        inputText.setDisabled(true);
        nuevoRegistro = registroAcreedorApp.findById(nuevoRegistro.getAcreedorId());
    }

    @Override
    public void onFind(ActionEvent actionEvent) {
        findRegistros();
    }

    public ActivoInactivo[] getAllEstado() {
        return ActivoInactivo.values();
    }


    public void findRegistros() {
        LazyAcreedorModel model = new LazyAcreedorModel(acreedorMapper, filtroBusqueda);
        lazyModel = model;
        detalle = new ArrayList<AcreedorSociedadDTO>();
    }


    @Override
    public void onClean(ActionEvent actionEvent) {
        registros = new ArrayList<AcreedorDTO>();
        detalle = new ArrayList<AcreedorSociedadDTO>();
        nuevoRegistro = new AcreedorDTO();
        filtroBusqueda = new AcreedorFlt();
    }

    @Override
    public void onPersist(ActionEvent actionEvent) {
        Acreedor acreedor = mapperService.map(nuevoRegistro, Acreedor.class);

        List<AcreedorSociedadDTO> acreedorSociedad = nuevoRegistro.getAcreedorSociedad();
        List<AcreedorSociedad> acreedorSociedadList = new ArrayList<AcreedorSociedad>();

        for (AcreedorSociedadDTO ac : acreedorSociedad) {
            ac.setAcreedorId(nuevoRegistro.getAcreedorId());
            acreedorSociedadList.add(mapperService.map(ac, AcreedorSociedad.class));
        }
        registroAcreedorApp.save(acreedor, acreedorSociedadList, updateMode);
//        findRegistros();
    }

    public void cleanActionSelect(ActionEvent actionEvent) {
        detallePickList = new ArrayList<SociedadDTO>();
        filtroPick = new SociedadFlt();
    }

    public void findActionSelect(ActionEvent actionEvent) {
        List<String> ids = new ArrayList<String>();
        for (AcreedorSociedadDTO item : nuevoRegistro.getAcreedorSociedad()) {
            ids.add(item.getSociedadId());
        }
        filtroPick.setNotInSociedadList(ids);
        detallePickList = sociedadMapper.findByFilter(filtroPick);
        if (detallePickList.size() == 0) {
            addMessage(noRecordFoundMsg, FacesMessage.SEVERITY_INFO);
        }
    }

    public void seleccionar(ActionEvent actionEvent) {

        List<String> seleccionados = new ArrayList<String>();

        for (SociedadDTO item : detallePickList) {
            if (item.getSeleccionado() != null && item.getSeleccionado()) {
                seleccionados.add(item.getSociedadId());
            }
        }
        List<SociedadDTO> registros = registroAcreedorApp.findByIdList(seleccionados);

        for (SociedadDTO sociedadDTO : registros) {
            AcreedorSociedadDTO acreedorSociedadDTO = new AcreedorSociedadDTO();
            acreedorSociedadDTO.setSociedad(sociedadDTO);
            acreedorSociedadDTO.setAcreedor(nuevoRegistro);
            nuevoRegistro.getAcreedorSociedad().add(acreedorSociedadDTO);
        }

        String dialogName = (String) actionEvent.getComponent().getAttributes().get("dialogName");
        if (dialogName != null) {
            executeModal(dialogName, false);
        }
    }

    public void onModify(RowEditEvent event) {
        try {
            updateMode = true;
//            acreedorService.saveSimple(nuevoRegistro, updateMode);
            addMessage(successfullyUpdateMsg);
        } catch (ApplicationException e) {
            if (e.getCause() != null) {
                addMessage(e.getMessage(), FacesMessage.SEVERITY_INFO);
            } else {
                addMessage(e.getMessage(), FacesMessage.SEVERITY_WARN, e.getParameters());
                addMessage("No ha sido efectuado cambio alguno", FacesMessage.SEVERITY_INFO);
            }
        }

    }


    public void deleteDetailAction(ActionEvent actionEvent) {
        nuevoRegistro.getSociedades().remove(nuevoRegistroDetalle);
    }

    @Override
    public void onDelete(ActionEvent actionEvent) {
        Acreedor acreedor = mapperService.map(nuevoRegistro, Acreedor.class);
        registroAcreedorApp.delete(acreedor);
        detalle = new ArrayList<AcreedorSociedadDTO>();

    }

    @Override
    protected void onDialogClose(CloseEvent event) {
        nuevoRegistro = new AcreedorDTO();
    }

    /*Getters and Setters*/

    public AcreedorFlt getFiltroBusqueda() {
        return filtroBusqueda;
    }

    public void setFiltroBusqueda(AcreedorFlt filtroBusqueda) {
        this.filtroBusqueda = filtroBusqueda;
    }

    public List<AcreedorDTO> getRegistros() {
        return registros;
    }

    public void setRegistros(List<AcreedorDTO> registros) {
        this.registros = registros;
    }

    public AcreedorDTO getNuevoRegistro() {
        return nuevoRegistro;
    }

    public void setNuevoRegistro(AcreedorDTO nuevoRegistro) {
        this.nuevoRegistro = nuevoRegistro;
    }

    public List<AcreedorSociedadDTO> getDetalle() {
        return detalle;
    }

    public void setDetalle(List<AcreedorSociedadDTO> detalle) {
        this.detalle = detalle;
    }

    public SociedadFlt getFiltroPick() {
        return filtroPick;
    }

    public void setFiltroPick(SociedadFlt filtroPick) {
        this.filtroPick = filtroPick;
    }

    public List<SociedadDTO> getDetallePickList() {
        return detallePickList;
    }

    public void setDetallePickList(List<SociedadDTO> detallePickList) {
        this.detallePickList = detallePickList;
    }


    public SociedadDTO getNuevoRegistroDetalle() {
        return nuevoRegistroDetalle;
    }

    public void setNuevoRegistroDetalle(SociedadDTO nuevoRegistroDetalle) {
        this.nuevoRegistroDetalle = nuevoRegistroDetalle;
    }

    public List<GrupoEmpresarialDTO> getCmbGrupoEmpresarial() {
        return cmbGrupoEmpresarial;
    }

    public void setCmbGrupoEmpresarial(List<GrupoEmpresarialDTO> cmbGrupoEmpresarial) {
        this.cmbGrupoEmpresarial = cmbGrupoEmpresarial;
    }

    public List<SociedadDTO> getCmbSociedad() {
        return cmbSociedad;
    }

    public void setCmbSociedad(List<SociedadDTO> cmbSociedad) {
        this.cmbSociedad = cmbSociedad;
    }

    public LazyDataModel<AcreedorDTO> getLazyModel() {
        return lazyModel;
    }

    public void setLazyModel(LazyDataModel<AcreedorDTO> lazyModel) {
        this.lazyModel = lazyModel;
    }

    public boolean isBorrarValor() {
        return borrarValor;
    }

    public void setBorrarValor(boolean borrarValor) {
        this.borrarValor = borrarValor;
    }
}
